Fix template Hono RPC response inference#1449
Conversation
- Anchor default JSON responses to schema-derived types - Derive template web types from `InferResponseType` - Probe default and auth Hono RPC response contracts
|
The latest Agentuity deployment details.
|
|
Warning Rate limit exceeded
To continue reviewing without waiting, purchase usage credits in the billing tab. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
📝 WalkthroughWalkthroughThis PR introduces Hono RPC type-based response typing across default and auth templates. API handlers now construct explicitly typed result objects; frontends derive types from API responses using ChangesAPI Response Typing & Type Verification
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
📦 Canary Packages Publishedversion: PackagesInstallAdd to your {
"dependencies": {
"@agentuity/opencode": "https://agentuity-sdk-objects.t3.storageapi.dev/npm/2.0.14-ade7ddd/agentuity-opencode-2.0.14-ade7ddd.tgz",
"@agentuity/auth": "https://agentuity-sdk-objects.t3.storageapi.dev/npm/2.0.14-ade7ddd/agentuity-auth-2.0.14-ade7ddd.tgz",
"@agentuity/cli": "https://agentuity-sdk-objects.t3.storageapi.dev/npm/2.0.14-ade7ddd/agentuity-cli-2.0.14-ade7ddd.tgz",
"@agentuity/runtime": "https://agentuity-sdk-objects.t3.storageapi.dev/npm/2.0.14-ade7ddd/agentuity-runtime-2.0.14-ade7ddd.tgz",
"@agentuity/claude-code": "https://agentuity-sdk-objects.t3.storageapi.dev/npm/2.0.14-ade7ddd/agentuity-claude-code-2.0.14-ade7ddd.tgz",
"@agentuity/coder": "https://agentuity-sdk-objects.t3.storageapi.dev/npm/2.0.14-ade7ddd/agentuity-coder-2.0.14-ade7ddd.tgz",
"@agentuity/postgres": "https://agentuity-sdk-objects.t3.storageapi.dev/npm/2.0.14-ade7ddd/agentuity-postgres-2.0.14-ade7ddd.tgz",
"@agentuity/schedule": "https://agentuity-sdk-objects.t3.storageapi.dev/npm/2.0.14-ade7ddd/agentuity-schedule-2.0.14-ade7ddd.tgz",
"@agentuity/sandbox": "https://agentuity-sdk-objects.t3.storageapi.dev/npm/2.0.14-ade7ddd/agentuity-sandbox-2.0.14-ade7ddd.tgz",
"@agentuity/core": "https://agentuity-sdk-objects.t3.storageapi.dev/npm/2.0.14-ade7ddd/agentuity-core-2.0.14-ade7ddd.tgz",
"@agentuity/queue": "https://agentuity-sdk-objects.t3.storageapi.dev/npm/2.0.14-ade7ddd/agentuity-queue-2.0.14-ade7ddd.tgz",
"@agentuity/react": "https://agentuity-sdk-objects.t3.storageapi.dev/npm/2.0.14-ade7ddd/agentuity-react-2.0.14-ade7ddd.tgz",
"@agentuity/webhook": "https://agentuity-sdk-objects.t3.storageapi.dev/npm/2.0.14-ade7ddd/agentuity-webhook-2.0.14-ade7ddd.tgz",
"@agentuity/schema": "https://agentuity-sdk-objects.t3.storageapi.dev/npm/2.0.14-ade7ddd/agentuity-schema-2.0.14-ade7ddd.tgz",
"@agentuity/evals": "https://agentuity-sdk-objects.t3.storageapi.dev/npm/2.0.14-ade7ddd/agentuity-evals-2.0.14-ade7ddd.tgz",
"@agentuity/frontend": "https://agentuity-sdk-objects.t3.storageapi.dev/npm/2.0.14-ade7ddd/agentuity-frontend-2.0.14-ade7ddd.tgz",
"@agentuity/migrate": "https://agentuity-sdk-objects.t3.storageapi.dev/npm/2.0.14-ade7ddd/agentuity-migrate-2.0.14-ade7ddd.tgz",
"@agentuity/workbench": "https://agentuity-sdk-objects.t3.storageapi.dev/npm/2.0.14-ade7ddd/agentuity-workbench-2.0.14-ade7ddd.tgz",
"@agentuity/db": "https://agentuity-sdk-objects.t3.storageapi.dev/npm/2.0.14-ade7ddd/agentuity-db-2.0.14-ade7ddd.tgz",
"@agentuity/drizzle": "https://agentuity-sdk-objects.t3.storageapi.dev/npm/2.0.14-ade7ddd/agentuity-drizzle-2.0.14-ade7ddd.tgz",
"@agentuity/email": "https://agentuity-sdk-objects.t3.storageapi.dev/npm/2.0.14-ade7ddd/agentuity-email-2.0.14-ade7ddd.tgz",
"@agentuity/vector": "https://agentuity-sdk-objects.t3.storageapi.dev/npm/2.0.14-ade7ddd/agentuity-vector-2.0.14-ade7ddd.tgz",
"@agentuity/keyvalue": "https://agentuity-sdk-objects.t3.storageapi.dev/npm/2.0.14-ade7ddd/agentuity-keyvalue-2.0.14-ade7ddd.tgz",
"@agentuity/coder-tui": "https://agentuity-sdk-objects.t3.storageapi.dev/npm/2.0.14-ade7ddd/agentuity-coder-tui-2.0.14-ade7ddd.tgz",
"@agentuity/task": "https://agentuity-sdk-objects.t3.storageapi.dev/npm/2.0.14-ade7ddd/agentuity-task-2.0.14-ade7ddd.tgz",
"@agentuity/server": "https://agentuity-sdk-objects.t3.storageapi.dev/npm/2.0.14-ade7ddd/agentuity-server-2.0.14-ade7ddd.tgz"
}
}Or install directly: bun add https://agentuity-sdk-objects.t3.storageapi.dev/npm/2.0.14-ade7ddd/agentuity-opencode-2.0.14-ade7ddd.tgz
bun add https://agentuity-sdk-objects.t3.storageapi.dev/npm/2.0.14-ade7ddd/agentuity-auth-2.0.14-ade7ddd.tgz
bun add https://agentuity-sdk-objects.t3.storageapi.dev/npm/2.0.14-ade7ddd/agentuity-cli-2.0.14-ade7ddd.tgz
bun add https://agentuity-sdk-objects.t3.storageapi.dev/npm/2.0.14-ade7ddd/agentuity-runtime-2.0.14-ade7ddd.tgz
bun add https://agentuity-sdk-objects.t3.storageapi.dev/npm/2.0.14-ade7ddd/agentuity-claude-code-2.0.14-ade7ddd.tgz
bun add https://agentuity-sdk-objects.t3.storageapi.dev/npm/2.0.14-ade7ddd/agentuity-coder-2.0.14-ade7ddd.tgz
bun add https://agentuity-sdk-objects.t3.storageapi.dev/npm/2.0.14-ade7ddd/agentuity-postgres-2.0.14-ade7ddd.tgz
bun add https://agentuity-sdk-objects.t3.storageapi.dev/npm/2.0.14-ade7ddd/agentuity-schedule-2.0.14-ade7ddd.tgz
bun add https://agentuity-sdk-objects.t3.storageapi.dev/npm/2.0.14-ade7ddd/agentuity-sandbox-2.0.14-ade7ddd.tgz
bun add https://agentuity-sdk-objects.t3.storageapi.dev/npm/2.0.14-ade7ddd/agentuity-core-2.0.14-ade7ddd.tgz
bun add https://agentuity-sdk-objects.t3.storageapi.dev/npm/2.0.14-ade7ddd/agentuity-queue-2.0.14-ade7ddd.tgz
bun add https://agentuity-sdk-objects.t3.storageapi.dev/npm/2.0.14-ade7ddd/agentuity-react-2.0.14-ade7ddd.tgz
bun add https://agentuity-sdk-objects.t3.storageapi.dev/npm/2.0.14-ade7ddd/agentuity-webhook-2.0.14-ade7ddd.tgz
bun add https://agentuity-sdk-objects.t3.storageapi.dev/npm/2.0.14-ade7ddd/agentuity-schema-2.0.14-ade7ddd.tgz
bun add https://agentuity-sdk-objects.t3.storageapi.dev/npm/2.0.14-ade7ddd/agentuity-evals-2.0.14-ade7ddd.tgz
bun add https://agentuity-sdk-objects.t3.storageapi.dev/npm/2.0.14-ade7ddd/agentuity-frontend-2.0.14-ade7ddd.tgz
bun add https://agentuity-sdk-objects.t3.storageapi.dev/npm/2.0.14-ade7ddd/agentuity-migrate-2.0.14-ade7ddd.tgz
bun add https://agentuity-sdk-objects.t3.storageapi.dev/npm/2.0.14-ade7ddd/agentuity-workbench-2.0.14-ade7ddd.tgz
bun add https://agentuity-sdk-objects.t3.storageapi.dev/npm/2.0.14-ade7ddd/agentuity-db-2.0.14-ade7ddd.tgz
bun add https://agentuity-sdk-objects.t3.storageapi.dev/npm/2.0.14-ade7ddd/agentuity-drizzle-2.0.14-ade7ddd.tgz
bun add https://agentuity-sdk-objects.t3.storageapi.dev/npm/2.0.14-ade7ddd/agentuity-email-2.0.14-ade7ddd.tgz
bun add https://agentuity-sdk-objects.t3.storageapi.dev/npm/2.0.14-ade7ddd/agentuity-vector-2.0.14-ade7ddd.tgz
bun add https://agentuity-sdk-objects.t3.storageapi.dev/npm/2.0.14-ade7ddd/agentuity-keyvalue-2.0.14-ade7ddd.tgz
bun add https://agentuity-sdk-objects.t3.storageapi.dev/npm/2.0.14-ade7ddd/agentuity-coder-tui-2.0.14-ade7ddd.tgz
bun add https://agentuity-sdk-objects.t3.storageapi.dev/npm/2.0.14-ade7ddd/agentuity-task-2.0.14-ade7ddd.tgz
bun add https://agentuity-sdk-objects.t3.storageapi.dev/npm/2.0.14-ade7ddd/agentuity-server-2.0.14-ade7ddd.tgz |
There was a problem hiding this comment.
🧹 Nitpick comments (2)
scripts/test-templates.ts (2)
537-624: 💤 Low valueOptional: deduplicate the boilerplate prelude across probes.
Both probe strings repeat the
hc/InferResponseType/ApiRouterimport block and theexpectTypedeclaration. As more templates gain probes, factoring this into a small helper (buildProbeSource(body: string): string) would keep them consistent and shorten diffs. Skip if you'd rather keep each probe self-contained for readability.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@scripts/test-templates.ts` around lines 537 - 624, The probe strings in getTemplateHonoRpcResponseTypeProbe repeat identical prelude lines (imports of hc/InferResponseType/ApiRouter and the expectType declaration); refactor by adding a helper function (e.g., buildProbeSource(body: string): string) and have getTemplateHonoRpcResponseTypeProbe return buildProbeSource(`<probe-specific body>`) for each case; update the 'default' and 'auth' branches to pass only the probe-specific type assertions and bodies to buildProbeSource and keep the shared prelude centralized while preserving existing probe bodies and names.
626-634: 💤 Low valueProbe path assumes every probed template has
src/web/.
writeFileSync(join(projectDir, 'src', 'web', 'hono-rpc-response-type-probe.ts'), …)will throwENOENTif a future template gains a probe but lackssrc/web/. Today both probed templates (default,auth) have that directory, so this is a future-proofing nit, not a current bug. Two cheap mitigations:♻️ Option A — ensure the directory exists
- const probePath = join(projectDir, 'src', 'web', 'hono-rpc-response-type-probe.ts'); - writeFileSync(probePath, probeSource); + const probeDir = join(projectDir, 'src', 'web'); + mkdirSync(probeDir, { recursive: true }); + const probePath = join(probeDir, 'hono-rpc-response-type-probe.ts'); + writeFileSync(probePath, probeSource);♻️ Option B — return `{ source, relativePath }` from the generator
Have
getTemplateHonoRpcResponseTypeProbereturn{ source, relativePath }so each template can place the probe wherever itstsconfigincludes (e.g.,src/api/...for non-web templates). Adjust the import path inside each probe accordingly.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@scripts/test-templates.ts` around lines 626 - 634, The probe writer verifyHonoRpcResponseTypes currently assumes src/web exists and can throw ENOENT; fix it by ensuring the target directory exists before writing the probe (call a recursive mkdir for the directory containing 'hono-rpc-response-type-probe.ts' inside verifyHonoRpcResponseTypes) or alternatively change the probe generator getTemplateHonoRpcResponseTypeProbe to return { source, relativePath } so callers write the probe to the returned relativePath (which will match the template's tsconfig) and create the containing directory if needed; update verifyHonoRpcResponseTypes to use the returned relativePath when present and always ensure the directory exists before writeFileSync.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@scripts/test-templates.ts`:
- Around line 537-624: The probe strings in getTemplateHonoRpcResponseTypeProbe
repeat identical prelude lines (imports of hc/InferResponseType/ApiRouter and
the expectType declaration); refactor by adding a helper function (e.g.,
buildProbeSource(body: string): string) and have
getTemplateHonoRpcResponseTypeProbe return buildProbeSource(`<probe-specific
body>`) for each case; update the 'default' and 'auth' branches to pass only the
probe-specific type assertions and bodies to buildProbeSource and keep the
shared prelude centralized while preserving existing probe bodies and names.
- Around line 626-634: The probe writer verifyHonoRpcResponseTypes currently
assumes src/web exists and can throw ENOENT; fix it by ensuring the target
directory exists before writing the probe (call a recursive mkdir for the
directory containing 'hono-rpc-response-type-probe.ts' inside
verifyHonoRpcResponseTypes) or alternatively change the probe generator
getTemplateHonoRpcResponseTypeProbe to return { source, relativePath } so
callers write the probe to the returned relativePath (which will match the
template's tsconfig) and create the containing directory if needed; update
verifyHonoRpcResponseTypes to use the returned relativePath when present and
always ensure the directory exists before writeFileSync.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 0196dba8-1090-4f18-b081-9f7bb5d25209
📒 Files selected for processing (4)
scripts/test-templates.tstemplates/auth/src/web/App.tsxtemplates/default/src/api/index.tstemplates/default/src/web/App.tsx
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
- GitHub Check: Windows WSL CLI Smoke Test
- GitHub Check: SDK Integration Test Suite
- GitHub Check: Cloud Deployment Tests
- GitHub Check: Agentuity Deployment
🧰 Additional context used
📓 Path-based instructions (5)
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (AGENTS.md)
Use Biome as code formatter with tabs (width 3), single quotes, semicolons, lineWidth 100, and trailingCommas es5
Files:
templates/auth/src/web/App.tsxtemplates/default/src/api/index.tsscripts/test-templates.tstemplates/default/src/web/App.tsx
**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{ts,tsx}: Use TypeScript Strict mode with ESNext target and bundler moduleResolution
UseStructuredErrorfrom@agentuity/corefor error handling
Files:
templates/auth/src/web/App.tsxtemplates/default/src/api/index.tsscripts/test-templates.tstemplates/default/src/web/App.tsx
templates/auth/src/**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (templates/auth/AGENTS.md)
Use Bun instead of NodeJS and TypeScript for all source code
Files:
templates/auth/src/web/App.tsx
templates/auth/src/web/**/*.{tsx,jsx}
📄 CodeRabbit inference engine (templates/auth/AGENTS.md)
templates/auth/src/web/**/*.{tsx,jsx}: Use<AuthView pathname={...}>to render the appropriate auth form (sign-in / sign-up / forgot-password / etc.) based on the current pathname
UseuseAuthenticate()hook to access{ user, isPending }for the signed-in user in React components
Use<AuthSwitch>wrapper to maintain previous auth state duringisPendingrefetches to prevent layout collapse on sign-in or sign-out
Files:
templates/auth/src/web/App.tsx
**/index.ts
📄 CodeRabbit inference engine (AGENTS.md)
Use named exports from package
index.tsfiles
Files:
templates/default/src/api/index.ts
🧠 Learnings (6)
📚 Learning: 2026-01-06T03:11:55.300Z
Learnt from: mcongrove
Repo: agentuity/sdk PR: 396
File: templates/default/src/web/App.tsx:111-111
Timestamp: 2026-01-06T03:11:55.300Z
Learning: In this repository's default template (Tailwind CSS v4 via tailwindcss/vite), gradient utilities such as bg-linear-to-*, bg-radial, and bg-conic are valid. Do not flag or replace these with bg-gradient-to-* in template files under templates/, including templates/default/src/web/App.tsx. Use bg-* utilities appropriate to Tailwind v4.
Applied to files:
templates/auth/src/web/App.tsxtemplates/default/src/web/App.tsx
📚 Learning: 2026-01-09T16:26:51.893Z
Learnt from: jhaynie
Repo: agentuity/sdk PR: 523
File: templates/_base/src/web/frontend.tsx:13-35
Timestamp: 2026-01-09T16:26:51.893Z
Learning: In web frontend code, prefer using the built-in Error class for runtime errors. Do not throw or re-export StructuredError from agentuity/core in web app code. Replace instances of StructuredError with new Error or custom error types that extend Error; ensure error handling logic remains intact and that error messages are descriptive. This guideline applies to all web UI TypeScript/TSX files that run in the browser and import StructuredError from agentuity/core.
Applied to files:
templates/auth/src/web/App.tsxtemplates/default/src/web/App.tsx
📚 Learning: 2025-12-19T14:19:33.765Z
Learnt from: jhaynie
Repo: agentuity/sdk PR: 259
File: packages/cli/src/cmd/build/vite/registry-generator.ts:306-312
Timestamp: 2025-12-19T14:19:33.765Z
Learning: Route files under src/api should use the .ts extension only (no .tsx) and regex patterns for such paths should anchor to \.ts$ (e.g., /\/.ts$/). Agent files may support both .ts and .tsx, but route files in the Agentuity SDK codebase are restricted to .ts. This guideline applies to all similar route files under src/api across the repository.
Applied to files:
templates/default/src/api/index.ts
📚 Learning: 2025-12-21T00:31:41.858Z
Learnt from: jhaynie
Repo: agentuity/sdk PR: 274
File: packages/cli/src/cmd/build/vite/server-bundler.ts:12-41
Timestamp: 2025-12-21T00:31:41.858Z
Learning: In Bun runtime, BuildMessage and ResolveMessage are global types and are not exported from the bun module. Do not import { BuildMessage } from 'bun' or similar; these types are available globally and should be used without import. This applies to all TypeScript files that target the Bun runtime within the repository.
Applied to files:
templates/default/src/api/index.tsscripts/test-templates.ts
📚 Learning: 2026-02-25T22:13:01.823Z
Learnt from: Huijiro
Repo: agentuity/sdk PR: 1063
File: apps/testing/vite-rsc-app/agentuity/src/api/index.ts:26-26
Timestamp: 2026-02-25T22:13:01.823Z
Learning: Agentuity SDK requires default exports for API route files (e.g., src/api/**/index.ts and src/api/**/route.ts) because the CLI's generateRouteRegistry relies on default exports to discover routes. Using named exports will skip route generation and lead to runtime 500 errors. This overrides typical guidance about named exports in index.ts files; ensure a default export is present in all relevant API route files under src/api/**/.
Applied to files:
templates/default/src/api/index.ts
📚 Learning: 2026-01-06T03:11:55.300Z
Learnt from: mcongrove
Repo: agentuity/sdk PR: 396
File: templates/default/src/web/App.tsx:111-111
Timestamp: 2026-01-06T03:11:55.300Z
Learning: In templates/default/src/web/App.tsx, keep using the Tailwind v4 class bg-linear-to-r for the background gradient. Do not suggest changing it to bg-gradient-to-r. This is a file-specific convention based on the project’s Tailwind version; for other files, verify the Tailwind version before proposing class changes.
Applied to files:
templates/default/src/web/App.tsx
🔇 Additional comments (5)
templates/auth/src/web/App.tsx (1)
10-19: LGTM — derived response type replaces hand-rolled interface.
ProtectedRouteResult = InferResponseType<typeof client.me.$get>keeps the UI shape in sync with the API schema, and the consumer (line 265) is already gated behindres.ok, so the union of error response types isn't an issue here.templates/default/src/api/index.ts (1)
63-67: LGTM — typed result objects anchor schema-derived inference.Materializing
result: TranslateResult/result: HistoryDatabeforec.json(result)is exactly what's needed to prevent theJSONValue[]widening reported in#1441. The schema-derived aliases now flow cleanly throughInferResponseTypeon the client. Nice fix.Also applies to: 139-176
templates/default/src/web/App.tsx (1)
16-18: LGTM — frontend types now derive from API responses.The
HistoryEntry = HistoryData['history'][number]derivation chains nicely offInferResponseType, and dropping the prior cast onsetTranslateResultconfirms the API side is now correctly typed. ThehandleClearHistorychange to consume the DELETE response avoids an extra round-trip vs. the previousfetchHistory()call.Also applies to: 34-60
scripts/test-templates.ts (2)
896-919: LGTM — Step 4.5 wiring is clean and skips correctly when no probe is defined.The conditional execution, step recording, and early-return on failure mirror the surrounding steps. Running the probe typecheck after Step 4 means a probe-only failure surfaces with a distinct step name in the summary, which is useful for triage.
583-619: ⚡ Quick winThe auth template properly exposes both
/healthand/meroutes with the expected response types. The test probe will typecheck correctly without changes.
- Share the Hono RPC probe prelude across templates - Carry probe source with its relative output path - Create probe directories before writing temp files
Summary
InferResponseTypeCloses #1441.
Why
The default template could let a loose API response type flow into the frontend as
JSONValue[], causing generated projects to fail on the history response.A simplified version of the bad shape:
That made the frontend see:
instead of the expected history entry array.
This change makes the API response satisfy the schema-derived type before it is
returned:
The frontend now consumes the Hono-inferred response type directly:
Testing
bunx biome format --write scripts/test-templates.ts templates/default/src/web/App.tsx templates/default/src/api/index.ts templates/auth/src/web/App.tsxbunx biome lint scripts/test-templates.ts templates/default/src/api/index.ts templates/default/src/web/App.tsx templates/auth/src/web/App.tsxbun scripts/test-templates.ts --skip-outdatedunknown[]fails typecheck at the API boundary/health.timestampasnumberfails the Hono RPC probegit diff --cached --checkReferences
InferResponseType: https://hono.dev/docs/guides/rpc#inferSummary by CodeRabbit
New Features
Tests